﻿using System;
using System.Data.Entity;
using XHouse.Model;
using XHouse.Model.Aparatos;
using XHouse.Model.Escenas;

namespace XHouse.Data
{
    public class XHouseDbContext : DbContext
    {
        public IDbSet<Escena> Escenas { get; set; }
        public IDbSet<Zona> Zonas { get; set; }
        public IDbSet<Aparato> Aparatos { get; set; }
        public IDbSet<Historial> Historial { get; set; }
        public IDbSet<Modulo> Modulos { get; set; }
        public IDbSet<TipoAparato> TipoAparatos { get; set; }
        public IDbSet<Imagen> Imagenes { get; set; }
        public IDbSet<EscenaAparatoTrigger> AparatoTriggers { get; set; }
        public IDbSet<EscenaTimerTrigger> TimerTriggers { get; set; }
        public IDbSet<EscenaAparatoEstado> EscenaAparatoEstados { get; set; }
        public IDbSet<Ambiente> Ambientes { get; set; }

        /// <summary>
        /// Constructs a new context instance using the given string as the name or connection string 
        /// for the database to which a connection will be made. For more information on how this is 
        /// used to create a connection, see the remarks section for <see cref="System.Data.Entity.DbContext"/>.
        /// </summary>
        /// <param name="connectionString"></param>
        public XHouseDbContext(string connectionString)
            : base(connectionString)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // Relación entre Aparato <-> Zona
            modelBuilder.Entity<Aparato>()
                        .HasRequired(x => x.Zona)
                        .WithMany(x => x.Aparatos)
                        .HasForeignKey(x => x.ZonaId);

            // Relación entre EscenaAparatoTrigger <-> Escena
            modelBuilder.Entity<EscenaAparatoTrigger>()
                        .HasRequired(x => x.Escena)
                        .WithMany(x => x.AparatoTriggers)
                        .HasForeignKey(x => x.EscenaId);

            // Relación entre EscenaAparatoTrigger <-> Aparato
            modelBuilder.Entity<EscenaAparatoTrigger>()
                        .HasRequired(x => x.Aparato)
                        .WithMany(x => x.AparatoTriggers)
                        .HasForeignKey(x => x.AparatoId);

            // Relación entre EscenaTimerTrigger <-> Escena
            modelBuilder.Entity<EscenaTimerTrigger>()
                        .HasRequired(x => x.Escena)
                        .WithMany(x => x.TimerTriggers)
                        .HasForeignKey(x => x.EscenaId);

            // Relación entre EscenaAparatoEstado <-> Escena
            modelBuilder.Entity<EscenaAparatoEstado>()
                        .HasRequired(x => x.Escena)
                        .WithMany(x => x.EstadoAparatos)
                        .HasForeignKey(x => x.EscenaId);

            // Desactivo lazy loading, esto se usa si queremos obtener los objetos con las dependencias llenas. Es mas lento.
            //this.Configuration.LazyLoadingEnabled = false;

            Database.SetInitializer(new Initializer());
        }

    }

    /// <summary>
    /// Inicialización de la base con datos de prueba. Para hacer mas fácil el desarrollo,
    /// el esquema de la base de datos se borra y se crea nuevamente en cada ejecución,
    /// así no hay que preocuparse cuando se modifican campos en el modelo.
    /// 
    /// AVISO: Esto debería desaparecer cuando la aplicación se ponga en producción.
    /// </summary>
    internal class Initializer : DropCreateDatabaseAlways<XHouseDbContext>
    {
        protected override void Seed(XHouseDbContext context)
        {
            /* TODO: Agregar usuarios, algunas zonas, aparatos, etc.
             * Una vez que esté definido bien el modelo, que no se genera mas la base de datos
             * automáticamente cada vez que inicia la aplicación, hay que hacer un script que 
             * inserte todos estos objetos en la base de datos. */

            /* Agrego a la base algunos de los tipos de aparatos de la lista */
            var ta = new TipoAparato
            {
                Nombre = "Toma Corriente",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Salida,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0,
                RangoTopeSuperior = 1,
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            var pir = new TipoAparato
            {
                Nombre = "Pir",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0,
                RangoTopeSuperior = 1,
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(pir);

            ta = new TipoAparato
            {
                Nombre = "Barrera infrarroja",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0,
                RangoTopeSuperior = 1,
                PuedeApagarse = true,
                EstadoApagado = 0
            };
            context.TipoAparatos.Add(ta);

            var tecla = new TipoAparato
            {
                Nombre = "Interruptor - Tecla",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0, //00 FIXME: Quizás esto tiene que ser un string
                RangoTopeSuperior = 1, //01 FIXME: Quizás esto tiene que ser un string
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(tecla);

            ta = new TipoAparato
            {
                Nombre = "Pulsador",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0, //00 FIXME: Quizás esto tiene que ser un string
                RangoTopeSuperior = 1, //01 FIXME: Quizás esto tiene que ser un string
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            ta = new TipoAparato
            {
                Nombre = "Pulsador incremental para luces",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Gradual,
                RangoTopeInferior = 0,
                RangoTopeSuperior = 100,
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            ta = new TipoAparato
            {
                Nombre = "Enchufe binario",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0, //00 FIXME: Quizás esto tiene que ser un string
                RangoTopeSuperior = 1, //01 FIXME: Quizás esto tiene que ser un string
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            ta = new TipoAparato
            {
                Nombre = "Enchufe regulado",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = 0,
                RangoTopeSuperior = 100,
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            ta = new TipoAparato
            {
                Nombre = "Termómetro",
                Descripcion = "",
                Habilitado = true,
                Conexion = TipoConexion.Entrada,
                Operacion = TipoOperacion.Binario,
                RangoTopeInferior = -60,
                RangoTopeSuperior = 120, //01 FIXME: Quizás esto tiene que ser un string
                PuedeApagarse = false // valor apagado 'nulo'
                //EstadoApagado = 0;  // no puede apagarse
            };
            context.TipoAparatos.Add(ta);

            /* 
             * Los siguientes objetos que agrego son a modo de ejemplo.
             */

            // Agrego una zona
            var zona = new Zona {Nombre = "Zona 1", Descripcion = "Descripcion de la zona 1"};
            context.Zonas.Add(zona);

            // Agrego un Ambiente
            var ambiente = new Ambiente { Nombre = "Cocina", Descripcion = "La única cocina que tiene la casa" };
            context.Ambientes.Add(ambiente);

            // Agrego un Modulo
            var modulo = new Modulo
                {
                    Nombre = "Modulo 1",
                    Descripcion = "Descripción del modulo 1",
                    Direccion = "123AF4",
                    Tipo = TipoModulo.Primario,
                    Ubicacion = "Ubicación del modulo 1"
                };
            context.Modulos.Add(modulo);

            context.SaveChanges();

            // Agrego dos aparatos conectados al módulo 1
            var aparato1 = new Aparato
                {
                    Nombre = "Pir",
                    Descripcion = "No se lo que es un pir",
                    EstadoActual = 0,
                    Habilitado = true,
                    ModuloId = modulo.Id,
                    ZonaId = zona.Id,
                    Numero = 2312,
                    TipoAparatoId = pir.Id,
                    AmbienteId = ambiente.Id
                };

            context.Aparatos.Add(aparato1);

            var aparato2 = new Aparato
            {
                Nombre = "Tecla del comedor",
                Descripcion = "Es una tecla que está enel comedor",
                EstadoActual = 0,
                Habilitado = true,
                ModuloId = modulo.Id,
                ZonaId = zona.Id,
                Numero = 2123,
                TipoAparatoId = tecla.Id,
                AmbienteId = ambiente.Id
            };

            context.Aparatos.Add(aparato2);

            /* Agrego un par de historiales */
            var his = new Historial
                {
                    Fecha = DateTime.Today.AddDays(-3),
                    ModuloNombre = "Modulo X",
                    AparatoNombre = "Aparato Y",
                    Accion = "Setear estado en 99",
                    UsuarioNombre = "Bichoscopio"
                };
            context.Historial.Add(his);

            his = new Historial
            {
                Fecha = DateTime.Today,
                ModuloNombre = "Modulo Pepito",
                AparatoNombre = "Porton del garage",
                Accion = "Cerrar",
                UsuarioNombre = "admin"
            };
            context.Historial.Add(his);

            /* Agrego una Escena */
            var esc = new Escena
                {
                    Nombre = "Cocina",
                    Descripcion = "Esta es la única cocina que hay en la casa"
                };
            context.Escenas.Add(esc);

            context.SaveChanges();
        }
    }
}
